/*
*	Copyright(c) 2020 lutianming email：641471957@qq.com
*
*	Sheeps may be copied only under the terms of the GNU Affero General Public License v3.0
*/

#include "framework.h"
#include "ServerProtocol.h"
#include "ServerSocksProxy.h"
#include "ServerHttp.h"
#include "ServerStress.h"
#include "ServerTask.h"
#include "SheepsFactory.h"
#include "ServerHook.h"

int  slogid = -1;
bool proxy_open = true;
bool proxy_hook = false;

const char* ca_crt = "-----BEGIN CERTIFICATE-----\n\
MIICyDCCAjGgAwIBAgIJAI6KZMZJFbFEMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNV\n\
BAYTAkNOMQswCQYDVQQIDAJTQzELMAkGA1UEBwwCWkcxHDAaBgNVBAoME0RlZmF1\n\
bHQgQ29tcGFueSBMdGQxFDASBgNVBAMMC3N1cGVyc2hlZXBzMR8wHQYJKoZIhvcN\n\
AQkBFhA2NDE0NzE5NTdAcXEuY29tMCAXDTIzMTAwOTExMzkxMVoYDzIxMjMwOTE1\n\
MTEzOTExWjB8MQswCQYDVQQGEwJDTjELMAkGA1UECAwCU0MxCzAJBgNVBAcMAlpH\n\
MRwwGgYDVQQKDBNEZWZhdWx0IENvbXBhbnkgTHRkMRQwEgYDVQQDDAtzdXBlcnNo\n\
ZWVwczEfMB0GCSqGSIb3DQEJARYQNjQxNDcxOTU3QHFxLmNvbTCBnzANBgkqhkiG\n\
9w0BAQEFAAOBjQAwgYkCgYEA54MG57smq3sOmpMJZBhi9sJP9OoUjSvrtsF74P2q\n\
6B0duK7pIrWDyGoEFtsHzN19fwPwtztYX42zcNsokWniHJUhXg2snunrLuLyeQ3H\n\
m2o2R0kina3oN41GFZDidJqwib0IK12mbp2Ld0Iv0zrhZMBEcCmJ5zCyNuw33RpU\n\
D/kCAwEAAaNQME4wHQYDVR0OBBYEFFpYKyt+G6Wd3cEZ+Vq15CAe5zxaMB8GA1Ud\n\
IwQYMBaAFFpYKyt+G6Wd3cEZ+Vq15CAe5zxaMAwGA1UdEwQFMAMBAf8wDQYJKoZI\n\
hvcNAQELBQADgYEANkvNzmj5G7QUk6XQLXLyGfrNnGKKfgqtEGbMa6OJABJjSSI9\n\
f8wsuoHbOKBXifYtdlpV7MW2WfNHuuB7HCU4WscLrGlwrKF+k9QfAQw/vjUQtDd5\n\
1ZU74nr/6w1fHA/96IfnHuS01AipVQy2BJSY+4s+h7dxkBrFq1CPw0zJPo0=\n\
-----END CERTIFICATE-----";

const char* user_crt = "-----BEGIN CERTIFICATE-----\n\
MIICnDCCAgWgAwIBAgIBATANBgkqhkiG9w0BAQsFADB8MQswCQYDVQQGEwJDTjEL\n\
MAkGA1UECAwCU0MxCzAJBgNVBAcMAlpHMRwwGgYDVQQKDBNEZWZhdWx0IENvbXBh\n\
bnkgTHRkMRQwEgYDVQQDDAtzdXBlcnNoZWVwczEfMB0GCSqGSIb3DQEJARYQNjQx\n\
NDcxOTU3QHFxLmNvbTAgFw0yMzEwMDkxMTQwNDFaGA8yMTIzMDkxNTExNDA0MVow\n\
XTELMAkGA1UEBhMCQ04xCzAJBgNVBAgMAlNDMQswCQYDVQQHDAJaRzEcMBoGA1UE\n\
CgwTRGVmYXVsdCBDb21wYW55IEx0ZDEWMBQGA1UEAwwNbXlzdXBlcnNoZWVwczCB\n\
nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAl2X5T2IRP52jzUWkFLAZ20CdyCug\n\
olpqCcD1DYq5Fhp5bm1iUBpz4tIqGaaWn2dqVW7OA1G+EQZwphZHSITeKuHVnwJ4\n\
I3ssoLTo8R7dHwv7cgJr1PL77agK25N2sXQNUzcAy7TnBCpM+HxtE5k37G/6DrSz\n\
0kHHiqN621hZxr8CAwEAAaNLMEkwCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwLwYD\n\
VR0RBCgwJoIQbXlzdXBlcnNoZWVwcy5jboISKi5teXN1cGVyc2hlZXBzLmNuMA0G\n\
CSqGSIb3DQEBCwUAA4GBAIbjXOQ1dU3pa4cZIPFaNIk4p05XzyOXB6NdVxEjwdoR\n\
oPyikj43jmBTikAGLHxuNWMjwaI9PrS0cZWVuvJ8dcgbgYGk3GHwrte8ka8DouSc\n\
4h7bP5/AJFMTY8l/E8vpgyqaPb7Q0QstZwAkxML4g/WgYwOBW8bXkTAXlXC1lvQQ\n\
-----END CERTIFICATE-----";

const char* pri_key = "-----BEGIN RSA PRIVATE KEY-----\n\
MIICXAIBAAKBgQCXZflPYhE/naPNRaQUsBnbQJ3IK6CiWmoJwPUNirkWGnlubWJQ\n\
GnPi0ioZppafZ2pVbs4DUb4RBnCmFkdIhN4q4dWfAngjeyygtOjxHt0fC/tyAmvU\n\
8vvtqArbk3axdA1TNwDLtOcEKkz4fG0TmTfsb/oOtLPSQceKo3rbWFnGvwIDAQAB\n\
AoGAJ01UlBP8MEyG+kHK34f7nlw+2Xjh4WOhRVjvBI3vkFpdDZqdu/ex/77ZKQGC\n\
9myNQRJbrqbotVi7o5IC/UNovMjaK4hH4epYuh4G9YY/m+iiuaLJjqoagpi83zbW\n\
fX5n90cZBugR9ArHkvxUBVXI/Csmq2MOtzDaoVtSqAzOd/ECQQDIjEvzma1umz+4\n\
Ty4X87sCie3FfrHeOQyor0YlIei3OTwUXWM3cpUL3+momLXQB/9+UanoyFOIo6fb\n\
hjLJNXeHAkEAwUKjPQr/jEt9/JHDbh6FPh1SnokM78HcNW5F8LxVs9LBg96W1ZbM\n\
6a0HEIPp1Y0hHGje9Gz9DUmXXVhi7aGVCQJBAJ7OOfaUYrmLRlH0oVNmNVg1UItr\n\
X/3Qvy10Xd9ZkqZENEcMDF0D5vKYRLa09oPdUXv9vsYOm9c/gNRc2CpspFECQFfQ\n\
gsITBEloaCfix+16msq9ojP9TE6JRRlWMRuRSFP8eQgFlX4aFqQ7hhFAD3mEtj3l\n\
fSGNgHKQNOIqblFR8ZkCQFOviD+LsSTB6eMESDLxhFR4p0LSlDe31zuVWiFi+6nz\n\
tJozH9A0mpkGizgFBM+I8I6yjMgO03xhD5iMGG5mRhs=\n\
-----END RSA PRIVATE KEY-----";

int	AgentTotalCount = 0;
std::vector<t_project_config*> ProjectConfig;
std::map<ServerProtocol*, std::string>* ProxyAddr = new std::map<ServerProtocol*, std::string>;

static void ServerProjectInit() {
	int i = 0;
	char key[16] = { 0x0 };
	const char* val, * parms;
	while (true)
	{
		memset(key, 0, sizeof(key));
		val = NULL;
		snprintf(key, sizeof(key), "%d", i);
		val = config_get_string_value("project", key, NULL);
		if (NULL == val)
			break;
		parms = config_get_string_value("parms", key, "");
		if (NULL == val)
			break;
		cJSON* item = cJSON_CreateObject();
		if (NULL == item)
			break;
		t_project_config* info = new t_project_config;
		info->name = std::string(val);
		info->parms = std::string(parms);
		
		t_agent_group* group = (t_agent_group*)malloc(sizeof(t_agent_group));
		if (!group) {
			printf("%s:%d memory error\n", __func__, __LINE__);
			break;
		}
		memset(group, 0x0, sizeof(t_agent_group));
		group->agents = new std::map<HSOCKET, t_sheeps_agent*>;
		info->groups.insert(std::make_pair(DEFAUT_GROUP, group));
		ProjectConfig.push_back(info);
		i++;
	}
}

bool ServerInit(char* configfile)
{
	const char* file = config_get_string_value("server", "manager_log_file", NULL);
	if (file) {
		char fullpath[256] = { 0x0 };
		snprintf(fullpath, sizeof(fullpath), "%s/%s", LogPath, file);
		int loglevel = config_get_int_value("server", "manager_log_level", LOG_NORMAL);
		int maxsize = config_get_int_value("server", "manager_log_size", 20);
		int timesplit = config_get_int_value("server", "manager_log_time", 0);
		int maxfile = config_get_int_value("server", "manager_log_maxfile", 1);
		slogid = RegisterLog(fullpath, loglevel, maxsize, timesplit, maxfile);
	}
	
	task_code_init();
	ServerProjectInit();
	proxy_open = config_get_bool_value("server", "proxy_open", true);
	proxy_hook = config_get_bool_value("server", "proxy_hook", false);
	return true;
}

ServerProtocol::ServerProtocol(){
}


ServerProtocol::~ServerProtocol(){
	if (this->http_proxy) {
		if (this->http_proxy->data) free(this->http_proxy->data);
		free(this->http_proxy);
	}
	if (this->socks5_proxy)	free(this->socks5_proxy);
	if (this->stressInfo)	free(this->stressInfo);
}


//固有函数，继承自基类
void ServerProtocol::ConnectionMade(HSOCKET hsock, PROTOCOL protocol)
{
	//LOG(slogid, LOG_DEBUG, "%s:%d proto[%p] sock[%p] protocol:%d peer_type:%d\r\n", __func__, __LINE__, this, hsock, type, this->peerType);
	switch (this->peerType)
	{
	case PEER_UNNOWN:
		this->initSock = hsock;
		return;
	case PEER_SOCKS5_PROXY:
		ProxyConnectionMade(hsock, this);
		return;
	case PEER_STRESS:
		return;
	case PEER_HTTP_PROXY:
		http_proxy_connection_made(hsock, this);
		return;
	default:
		break;
	}
	//LOG(slogid, LOG_DEBUG, "new unnkown connetion made: %s:%d\r\n", ip, port);
	HsocketClose(hsock);
}

void ServerProtocol::ConnectionFailed(HSOCKET hsock, int err)
{
	//LOG(slogid, LOG_DEBUG, "%s:%d proto[%s] sock[%p]\r\n", __func__, __LINE__, this, hsock);
	switch (this->peerType)
	{
	case PEER_SOCKS5_PROXY:
		ProxyConnectionFailed(hsock, this);
		return;
	case PEER_HTTP_PROXY:
		http_proxy_connection_faile(hsock, this);
		return;
	default:
		break;
	}
	HsocketClose(this->initSock);
}

void ServerProtocol::ConnectionClosed(HSOCKET hsock, int err)
{
	//LOG(slogid, LOG_DEBUG, "%s:%d proto[%p] sock[%p]\r\n", __func__, __LINE__, this, hsock);
	if (this->peerType == PEER_SOCKS5_PROXY)
	{
		ProxyConnectionClosed(hsock, this);
	}
	else if (this->peerType == PEER_STRESS)
	{
		StressConnectionClosed(hsock, this);
	}
	else if (this->peerType == PEER_HTTP || this->peerType == PEER_UNNOWN)
	{
		this->initSock = NULL;
	}
	else if (this->peerType == PEER_HTTP_PROXY) 
	{
		http_proxy_connection_closed(hsock, this);
	}
}

void ServerProtocol::ConnectionRecved(HSOCKET hsock, const char* data, int len)
{
	if (hsock == this->initSock){
		int clen = 0;
		while (len){
			clen = this->CheckRequest(hsock, data, len);
			if (clen > 0){
				len = HsocketPopBuf(hsock, clen);
			}
			else if (clen < 0){
				HsocketClose(hsock);
				break;
			}
			else
				break;
		}
	}
	else{
		switch (this->peerType){
		case PEER_SOCKS5_PROXY:
			CheckPoxyRequest(hsock, this, data, len);
			break;
		case PEER_HTTP_PROXY:
			http_proxy_server_connection_recved(hsock, this, data, len);
			break;
		default:
			break;
		}
		HsocketPopBuf(hsock, len);
	}
}

//自定义类成员函数
int ServerProtocol::CheckRequest(HSOCKET hsock, const char* data, int len)
{
	int clen = -1;
	do_switch:
	switch (this->peerType)
	{
	case PEER_UNNOWN:
		if (*data == 0x5 && proxy_open)
		{
			this->peerType = PEER_SOCKS5_PROXY;
			this->socks5_proxy = (h_SOCKS5_PROXY)malloc(sizeof(t_socks5_proxy));
			if (this->socks5_proxy == NULL)
				return -1;
			memset(this->socks5_proxy, 0x0, sizeof(t_socks5_proxy));
			this->socks5_proxy->retry = 3;
		}
		else if (strncasecmp(data, "GET", 3) == 0 || strncasecmp(data, "POST", 4) == 0 || strncasecmp(data, "HEAD", 4) == 0 ||
			strncasecmp(data, "PUT", 3) == 0 || strncasecmp(data, "DELETE", 6) == 0 || strncasecmp(data, "CONNECT", 7) == 0 ||
			strncasecmp(data, "OPTIONS", 7) == 0 || strncasecmp(data, "TRACE", 5) == 0 || strncasecmp(data, "PATCH", 5) == 0)
		{
			this->peerType = PEER_HTTP;
		}
		else if (strncasecmp(data, "sheeps", 6) == 0)
		{
			this->peerType = PEER_STRESS;
			this->stressInfo = (h_SHEEPS_AGENT)malloc(sizeof(t_sheeps_agent));
			if (this->stressInfo == NULL)
				return -1;
			memset(this->stressInfo, 0x0, sizeof(t_sheeps_agent));
			HsocketSend(hsock, "sheeps", 6);
			HsocketPopBuf(hsock, 6);
#if defined(OPENSSL_SUPPORT) && defined(SHEEPS_SSL)
			HsocketSSLCreate(hsock, SSL_SERVER, 0, NULL, user_crt, pri_key);
#endif
			clen = 0;
			break;
		}
		else
		{
			this->peerType = PEER_UNDEFINE;
		}
		goto do_switch;
	case PEER_SOCKS5_PROXY:
		clen = CheckPoxyRequest(hsock, this, data, len);
		break;
	case PEER_STRESS:
		clen = CheckStressRequest(hsock, this, data, len);
		break;
	case PEER_HTTP:
		clen = CheckHttpRequest(hsock, this, data, len);
		break;
	case PEER_HTTP_PROXY:
		clen = http_proxy_client_connection_recved(hsock, this, data, len);
		break;
	case PEER_UNDEFINE:
		HsocketSend(hsock, data, len);
		clen = len;
		break;
	default:
		break;
	}
	//LOG(slogid, LOG_DEBUG, "%p peer_type[%d]\r\n", hsock, this->peerType);
	return clen;
}
